package com.ndbg.demo.exception.base;

import com.ndbg.demo.entity.MessageContext;
import com.ndbg.demo.exception.FailureCause;
import com.ndbg.demo.exception.IFailureCauser;
import org.apache.commons.text.StringSubstitutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public abstract class AbstractCustomException extends RuntimeException implements IFailureCauser {
    private static final Logger log = LoggerFactory.getLogger(AbstractCustomException.class);

    public AbstractCustomException(String message) {
        super(message);
    }

    public AbstractCustomException(String message, Throwable cause) {
        super(message, cause);
    }

    /**
     * 获取错误编码
     *
     * @return int
     */
    public int getExceptionCode() {
        return 0;
    }

    /**
     * 获取枚举code
     *
     * @param enums 枚举类
     * @return code
     */
    protected static Integer getCode(Enum<? extends FailureCause> enums) {
        FailureCause failureCause = (FailureCause) enums;
        return failureCause.getCode();
    }

    /**
     * 获取枚举消息
     *
     * @param enums 枚举类
     * @return message
     */
    protected static String getMessage(Enum<? extends FailureCause> enums) {
        FailureCause failureCause = (FailureCause) enums;
        return failureCause.getMessage();
    }

    /**
     * 错误消息构建
     *
     * @param enums      枚举类key
     * @param contextArr 自行构建上下文信息【k：枚举类需要替换的内容 v：实际值】
     * @return 真实错误信息
     */
    protected static String buildMessage(Enum<? extends FailureCause> enums, MessageContext[] contextArr) {
        String message = getMessage(enums);
        List<MessageContext> collectList = Arrays.stream(contextArr)
                .filter(context -> message.contains(context.getK()) && !ObjectUtils.isEmpty(context.getV()))
                .collect(Collectors.toList());

        if (contextArr.length != collectList.size()) {
            log.error("expectation:{}", message);
            log.error("actual:{}", Arrays.stream(contextArr).map(MessageContext::getK).collect(Collectors.toList()).toString());
            throw new IllegalArgumentException("invoke error,the expected value is not equal to the expected value");
        }

        Map<String, Object> map = new HashMap<>();
        collectList.forEach(context -> map.put(context.getK(), context.getV()));
        return new StringSubstitutor(map).replace(message);
    }
}
